#include "CalEvent.hh"

using namespace std;

CalEvent::CalEvent()
{
  fCal = NULL;
  fFBarrel.clear();
  fBBarrel.clear();
  fBCD.clear();
  fCluster.clear();
}
CalEvent::CalEvent(Calibration* cal, Settings *settings) : fCal(cal), fSettings(settings) {
  fFBarrel.clear();
  fBBarrel.clear();
  fBCD.clear();
  fCluster.clear();
}
CalEvent::~CalEvent(){
}
void CalEvent::Clear(){
  fFBarrel.clear();
  fBBarrel.clear();
  fBCD.clear();
  fCluster.clear();
}
void CalEvent::SetTime(long long EbisTime, long long T1Time, long long SuperCycleTime){
    fEbisTime = EbisTime;
    fT1Time = T1Time;
    fSuperCycleTime = SuperCycleTime;
}
void CalEvent::SetFBarrel(int quadr, vector<vector<unsigned short> > &adcval, vector<long long> time){
  int mod = fSettings->RearECDMod(quadr);
  int dEchan = fSettings->FDeltaChan(quadr);
  int Echan = fSettings->FEChan(quadr);
  int stripmod = fSettings->FStripMod(quadr);
  int firststrip = fSettings->FFirstStrip(quadr);
  
  if( (mod<0) || (dEchan<0) || (Echan<0) || (stripmod<0) || (firststrip<0) ){
    cerr<<"Error in Settings Quadrant "<<quadr<<" RearECDMod "<<mod<<" FDeltaChan "<<dEchan<<" FEChan "<<Echan<<" FStripMod "<<stripmod<<" FFirstStrip "<<firststrip<<endl;
    return;
  }
  double rear = fCal->RemoveOffset(1,quadr,adcval[mod][dEchan]);
  if(rear<0)
    return;
  if(fSettings->VLevel()>3)
    cout << "rear " << rear << endl;
  int higheststrip = -1;
  int secondstrip = -1;
  int thirdstrip = -1;
  double highestenergy = 0.;
  double secondenergy = 0.;
  double thirdenergy = 0.;
    
  Barrel ForwardBarrel;
  if(fSettings->VLevel()>3)
    cout << "Quadrant " << quadr << " Module " << mod << endl;
  
  ForwardBarrel.ID(quadr);
  ForwardBarrel.Time(time[mod]);
  ForwardBarrel.SetEdet(fCal->AdcEnergy(mod,Echan,adcval[mod][Echan]));


  for(int i=firststrip;i<firststrip+16;i++){
    if( (fCal->AdcEnergy(stripmod, i, adcval[stripmod][i]) > highestenergy) && (adcval[stripmod][i]<3800) && (adcval[stripmod][i]>fSettings->FDeltaThresh(quadr)) ){
      thirdstrip = secondstrip;
      secondstrip = higheststrip;
      higheststrip = i;

      thirdenergy = secondenergy;
      secondenergy = highestenergy;
      highestenergy = fCal->AdcEnergy(stripmod, i, adcval[stripmod][i]);
    }
    else if( (fCal->AdcEnergy(stripmod, i, adcval[stripmod][i]) > secondenergy) && (adcval[stripmod][i]<3800) && (adcval[stripmod][i]>fSettings->FDeltaThresh(quadr)) ){
      thirdstrip = secondstrip;
      secondstrip = i;

      thirdenergy = secondenergy;
      secondenergy = fCal->AdcEnergy(stripmod, i, adcval[stripmod][i]);
    }        
  }
  if(higheststrip>-1){
    
    if( (secondenergy/highestenergy > fSettings->MinimalStripRatio(quadr) ) && ( secondenergy/rear > fSettings->MinimalStripRearRatio(quadr) ) ){
      secondenergy = fCal->StripPos(stripmod, secondstrip, adcval[stripmod][secondstrip],rear);
      if(fSettings->VLevel()>0){
	cout << "2energy = " <<setprecision(2)<< secondenergy << " 1energy = " <<setprecision(2)<< highestenergy << " ratio = " <<setprecision(2)<< secondenergy/highestenergy << endl;
	cout << "limit = " <<setprecision(2)<< fSettings->MinimalStripRatio(quadr) << endl;
	cout << "2strip nr = " << secondstrip << " 1strip nr = " << higheststrip << endl;
      }

      ForwardBarrel.SetMult(2);    
      if( (thirdenergy/highestenergy > fSettings->MinimalStripRatio(quadr) ) && ( thirdenergy/rear > fSettings->MinimalStripRearRatio(quadr) ) ){ // three or more hits 	
	if(fSettings->VLevel()>3)
	  cout << "Multiplicity 3, energy 3 " << thirdenergy << endl;
	ForwardBarrel.SetMult(3);
      }
      if(fSettings->VLevel()>3)
	cout << "Multiplicity 2, energy 2 " << secondenergy << " energy 1 " << highestenergy << endl;

      highestenergy = fCal->StripPos(stripmod, higheststrip, adcval[stripmod][higheststrip],rear); 

      rear = fCal->RearCorrection(rear, highestenergy, quadr, true);
      highestenergy = fCal->StripPos(stripmod, higheststrip, adcval[stripmod][higheststrip],rear); 

      secondenergy = fCal->StripPos(stripmod, secondstrip, adcval[stripmod][secondstrip],rear);

      ForwardBarrel.Set2Strips(higheststrip-firststrip, highestenergy, secondstrip-firststrip, secondenergy, (abs(higheststrip-secondstrip)==1));
    }
    else{
      highestenergy = fCal->StripPos(stripmod, higheststrip, adcval[stripmod][higheststrip],rear); 
      rear = fCal->RearCorrection(rear, highestenergy, quadr, true);
      highestenergy = fCal->StripPos(stripmod, higheststrip, adcval[stripmod][higheststrip],rear); 
      ForwardBarrel.SetStrip(higheststrip-firststrip, highestenergy);
      ForwardBarrel.SetMult(1);
      if(fSettings->VLevel()>3)
	cout << "Multiplicity 1, energy " << highestenergy << endl;
    }
  }
  else{
    ForwardBarrel.SetMult(0);
  }
  if(fSettings->VLevel()>2)
    cout << "rear " << rear << " highestenergy " << highestenergy << " quadr " << quadr << " higheststrip " << higheststrip << endl;


  //cout << "adcval["<<mod<<"]["<<dEchan<<"]" << adcval[mod][dEchan] << " -> rear " << rear << " -> cal " << fCal->DeltaEnergy(mod,dEchan,rear) << endl;
  //ForwardBarrel.SetRear(fCal->AdcEnergy(mod,dEchan,adcval[mod][dEchan]));
  ForwardBarrel.SetRear(fCal->DeltaEnergy(mod,dEchan,rear));

  fFBarrel.push_back(ForwardBarrel);  

}


void CalEvent::SetBBarrel(int quadr, vector<vector<unsigned short> > &adcval, vector<long long> time){
  int mod = fSettings->RearECDMod(quadr);
  int dEchan = fSettings->BDeltaChan(quadr);
  int Echan = fSettings->BEChan(quadr);
  int stripmod = fSettings->BStripMod(quadr);
  int firststrip = fSettings->BFirstStrip(quadr);
  
  if( (mod<0) || (dEchan<0) || (Echan<0) || (stripmod<0) || (firststrip<0) ){
    cerr<<"Error in Settings Quadrant "<<quadr<<" RearECDMod "<<mod<<" BDeltaChan "<<dEchan<<" BEChan "<<Echan<<" BStripMod "<<stripmod<<" BFirstStrip "<<firststrip<<endl;
    return;
  }
  
  double rear = fCal->RemoveOffset(0,quadr,adcval[mod][dEchan]);
  if(rear<0)
    return;

  if(fSettings->VLevel()>3)
    cout << "rear " << rear << endl;
  int higheststrip = -1;
  int secondstrip = -1;
  int thirdstrip = -1;
  double highestenergy = 0.;
  double secondenergy = 0.;
  double thirdenergy = 0.;
    
  Barrel BackwardBarrel;
  if(fSettings->VLevel()>3)
    cout << "Quadrant " << quadr << " Module " << mod << endl;
  
  BackwardBarrel.ID(quadr);
  BackwardBarrel.Time(time[mod]);
  BackwardBarrel.SetEdet(fCal->AdcEnergy(mod,Echan,adcval[mod][Echan]));


  for(int i=firststrip;i<firststrip+16;i++){
    if( (fCal->AdcEnergy(stripmod, i, adcval[stripmod][i]) > highestenergy) && (adcval[stripmod][i]<3800) && (adcval[stripmod][i]>fSettings->BDeltaThresh(quadr)) ){
      thirdstrip = secondstrip;
      secondstrip = higheststrip;
      higheststrip = i;

      thirdenergy = secondenergy;
      secondenergy = highestenergy;
      highestenergy = fCal->AdcEnergy(stripmod, i, adcval[stripmod][i]);
    }
    else if( (fCal->AdcEnergy(stripmod, i, adcval[stripmod][i]) > secondenergy) && (adcval[stripmod][i]<3800) && (adcval[stripmod][i]>fSettings->BDeltaThresh(quadr)) ){
      thirdstrip = secondstrip;
      secondstrip = i;

      thirdenergy = secondenergy;
      secondenergy = fCal->AdcEnergy(stripmod, i, adcval[stripmod][i]);
    }    
  }
  if(higheststrip>-1){
    
    if( (secondenergy/highestenergy > fSettings->MinimalStripRatio(quadr) ) && ( secondenergy/rear > fSettings->MinimalStripRearRatio(quadr) ) ){
      if(fSettings->VLevel()>3){
	cout << "2energy = " <<setprecision(2)<< secondenergy << " 1energy = " <<setprecision(2)<< highestenergy << " ratio = " <<setprecision(2)<< secondenergy/highestenergy << endl;
	cout << "limit = " <<setprecision(2)<< fSettings->MinimalStripRatio(quadr) << endl;
      }
      secondenergy = fCal->StripPos(stripmod, secondstrip, adcval[stripmod][secondstrip],rear);

      BackwardBarrel.SetMult(2);    
      if( (thirdenergy/highestenergy > fSettings->MinimalStripRatio(quadr) ) && ( thirdenergy/rear > fSettings->MinimalStripRearRatio(quadr) ) ){ // three or more hits 	
	if(fSettings->VLevel()>3)
	  cout << "Multiplicity 3, energy 3 " << thirdenergy << endl;
	BackwardBarrel.SetMult(3);
      }
      if(fSettings->VLevel()>3)
	cout << "Multiplicity 2, energy 2 " << secondenergy << " energy 1 " << highestenergy << endl;

      highestenergy = fCal->StripPos(stripmod, higheststrip, adcval[stripmod][higheststrip],rear); 

      rear = fCal->RearCorrection(rear, highestenergy, quadr, false);
      highestenergy = fCal->StripPos(stripmod, higheststrip, adcval[stripmod][higheststrip],rear); 

      secondenergy = fCal->StripPos(stripmod, secondstrip, adcval[stripmod][secondstrip],rear);

      BackwardBarrel.Set2Strips(higheststrip-firststrip, highestenergy, secondstrip-firststrip, secondenergy, (abs(higheststrip-secondstrip)==1));
    }
    else{
      highestenergy = fCal->StripPos(stripmod, higheststrip, adcval[stripmod][higheststrip],rear); 
      rear = fCal->RearCorrection(rear, highestenergy, quadr, false);
      highestenergy = fCal->StripPos(stripmod, higheststrip, adcval[stripmod][higheststrip],rear); 
      BackwardBarrel.SetStrip(higheststrip-firststrip, highestenergy);
      BackwardBarrel.SetMult(1);
      if(fSettings->VLevel()>3)
	cout << "Multiplicity 1, energy " << highestenergy << endl;
    }
  }
  else{
    BackwardBarrel.SetMult(0);

  }
  if(fSettings->VLevel()>2)
    cout << "rear " << rear << " highestenergy " << highestenergy << " quadr " << quadr << " higheststrip " << higheststrip << endl;

  //BackwardBarrel.SetRear(fCal->AdcEnergy(mod,dEchan,adcval[mod][dEchan]));
  BackwardBarrel.SetRear(fCal->DeltaEnergy(mod,dEchan,rear));

  fBBarrel.push_back(BackwardBarrel);
}
void CalEvent::SetBCD(int quadr, vector<vector<unsigned short> > &adcval, vector<long long> time, Mux* mux){
  int modRing = fSettings->RearECDModRing(quadr);
  int modStrip = fSettings->RearECDModStrip(quadr);
  int Echan = fSettings->CDEChan(quadr);

  if( (modRing<0) || (Echan<0) || (modStrip<0) ){
    cerr<<"Error in Settings Quadrant "<<quadr<<" RearECDMod "<<modRing<<" CDEChan "<<Echan<<endl;
    return;
  }

  Annular BackwardCD;
  BackwardCD.ID(quadr);
  BackwardCD.Time(time[modRing]);
  BackwardCD.SetEdet(fCal->AdcEnergy(modRing,Echan,adcval[modRing][Echan]));

  int firstHit=-1;
  int secondHit=-1;

  unsigned short firstStripPos = adcval[modStrip][fSettings->CDStripPos(quadr/2,0)];
  unsigned short secondStripPos = adcval[modStrip][fSettings->CDStripPos(quadr/2,1)];

  unsigned short firstStripE = adcval[modStrip][fSettings->CDStripEnergy(quadr/2,0)];
  unsigned short secondStripE = adcval[modStrip][fSettings->CDStripEnergy(quadr/2,1)];

  unsigned short firstRingPos = adcval[modRing][fSettings->CDRingPos(quadr/2,0)];
  unsigned short secondRingPos = adcval[modRing][fSettings->CDRingPos(quadr/2,1)];

  unsigned short firstRingE = adcval[modRing][fSettings->CDRingEnergy(quadr/2,0)];
  unsigned short secondRingE = adcval[modRing][fSettings->CDRingEnergy(quadr/2,1)];
  
  //cout << "first strip: pos " << firstStripPos << " energy: " << firstStripE << endl;

  if(firstStripE>fSettings->CDDeltaThreshStrip(quadr/2))  
	 firstHit = mux->StripNr(firstStripPos, quadr, true);
  if(secondStripE>fSettings->CDDeltaThreshStrip(quadr/2))    
    secondHit = mux->StripNr(secondStripPos, quadr, true);
  if( (firstHit>-1) && (firstHit<16) ){
    if(fSettings->VLevel()>3)
      cout << "first strip: nr " << firstHit << " energy: " << firstStripE << endl;
    if( (secondHit>-1) && (secondHit<16) ){
      BackwardCD.Set2Strips(firstHit, fCal->CDStripEnergy(quadr, firstHit, firstStripE), secondHit, fCal->CDStripEnergy(quadr, secondHit, secondStripE));
    }
    else{
      BackwardCD.SetStrip(firstHit, fCal->CDStripEnergy(quadr, firstHit, firstStripE));
    }
  }

  firstHit=-1;
  secondHit=-1;

  if(firstRingE>fSettings->CDDeltaThreshRing(quadr/2))  
    firstHit = mux->StripNr(firstRingPos, quadr, false);
  if(secondRingE>fSettings->CDDeltaThreshRing(quadr/2))  
    secondHit = mux->StripNr(secondRingPos, quadr, false);

  if( (firstHit>-1) && (firstHit<16) ){
    if( (secondHit>-1) && (secondHit<16) ){
      BackwardCD.Set2Rings(firstHit, fCal->CDRingEnergy(quadr, firstHit, firstRingE), secondHit, fCal->CDRingEnergy(quadr, secondHit, secondRingE));
    }
    else{
      BackwardCD.SetRing(firstHit, fCal->CDRingEnergy(quadr, firstHit, firstRingE));
    }
  }
  
  fBCD.push_back(BackwardCD);

}
//void CalEvent::SetCluster(DgfData dgf){
void CalEvent::SetCluster(int cluster, vector<DgfData> dgf){
  Germanium Cluster;
  Cluster.SetCluID(cluster);
  for(int i=0;i<dgf.size();i++){
    double energy = fCal->DgfEnergy(dgf[i].ModuleNumber(), dgf[i].Channel(), dgf[i].Energy());
    if(dgf[i].Channel()==fSettings->CoreChannel() && dgf[i].ModuleNumber()%2==0){ //core

      if(fSettings->Crystal(dgf[i].ModuleNumber()) > 2){
	cerr << "Error Crystal ID >2 shoudl be 0 A ,1 B, 2 C  is " << fSettings->Crystal(dgf[i].ModuleNumber()) << endl; 
      }
      Cluster.SetCore(fSettings->Crystal(dgf[i].ModuleNumber()), energy, (MyTime_t) dgf[i].Time()); //to do walkcorrection of time here!
      if(fSettings->VLevel()>3)
	cout << " core: crystal " << fSettings->Crystal(dgf[i].ModuleNumber()) << " energy " << energy << " time " << dgf[i].Time() << endl;
    }
    else{ //segment
      if(fSettings->Crystal(dgf[i].ModuleNumber()) > 2){
	cerr << "Error Crystal ID >2 shoudl be 0 A ,1 B, 2 C  is " << fSettings->Crystal(dgf[i].ModuleNumber()) << endl; 
      }
      Cluster.SetSegment(fSettings->Crystal(dgf[i].ModuleNumber()), fSettings->Segment(dgf[i].ModuleNumber(), dgf[i].Channel()), energy, (MyTime_t) dgf[i].Time());
      if(fSettings->VLevel()>3)
	cout << " segemnt: crystal " << fSettings->Crystal(dgf[i].ModuleNumber()) << " segment " << fSettings->Segment(dgf[i].ModuleNumber(), dgf[i].Channel()) << " energy " << energy << " time " << dgf[i].Time() << endl;
    }
  }
  /*
  Cluster.SetCluID(fSettings->Cluster(dgf.ModuleNumber()));
  double energy = fCal->DgfEnergy(dgf.ModuleNumber(), dgf.Channel(), dgf.Energy());
  if(energy<10)
    return;
  if(dgf.Channel()==fSettings->CoreChannel() && dgf.ModuleNumber()%2==0){ //core
    Cluster.SetCore(fSettings->Crystal(dgf.ModuleNumber()), energy, (MyTime_t) dgf.Time());
  }
  else{ //segment
    Cluster.SetSegment(fSettings->Crystal(dgf.ModuleNumber()), fSettings->Segment(dgf.ModuleNumber(), dgf.Channel()), energy, (MyTime_t) dgf.Time());
  }
  */
  if(fSettings->VLevel()>1 && Cluster.strange ==1)
    Cluster.PrintCluster();

  fCluster.push_back(Cluster);		   
};
